import { useEffect, useRef, useState } from "react";

const getMediaRecorder = () =>
  new Promise<MediaRecorder>((resolve, reject) => {
    if (navigator.mediaDevices.getUserMedia) {
      navigator.mediaDevices.getUserMedia({ audio: true }).then(
        (stream) => {
          resolve(new MediaRecorder(stream));
        },
        (e) => {
          console.error("授权失败", e);
          reject(new Error("授权失败"));
        },
      );
    } else {
      reject(new Error("浏览器不支持 getUserMedia"));
    }
  });

type Options = {
  onOk: (audio: Blob) => void;
  onError?: (error: ErrorEvent) => void;
};

export default function useAudioRecorder({ onOk, onError }: Options) {
  const audioRecorder = useRef<MediaRecorder | null>(null);
  const audioChunks = useRef<Blob[]>([]);
  const [audioStatus, setAudioStatus] = useState<RecordingState>("inactive");

  const handleStart = () => {
    audioChunks.current = [];
    setAudioStatus("recording");
  };

  const handleDataAvailable = (e: BlobEvent) => {
    audioChunks.current.push(e.data);
  };

  const handleStop = () => {
    const audioBlob = new Blob(audioChunks.current, {
      type: "audio/ogg; codecs=opus",
    });
    setAudioStatus("inactive");
    audioChunks.current = [];
    onOk(audioBlob);
  };

  const handleError = (e: ErrorEvent) => {
    onError?.(e);
    setAudioStatus("inactive");
    audioChunks.current = [];
  };

  const handlePause = () => {
    setAudioStatus("paused");
  };

  const handleResume = () => {
    setAudioStatus("recording");
  };

  useEffect(() => {
    getMediaRecorder()
      .then((ar) => {
        ar.onstart = handleStart;
        ar.ondataavailable = handleDataAvailable;
        ar.onstop = handleStop;
        ar.onpause = handlePause;
        ar.onresume = handleResume;
        ar.onerror = handleError;
        audioRecorder.current = ar;
      })
      .catch((err) => {
        onError?.(err);
      });

    return () => {
      audioRecorder.current?.stop();
    };
  }, []);

  const start = () => {
    audioRecorder.current?.start();
  };

  const stop = () => {
    audioRecorder.current?.stop();
  };

  const pause = () => {
    audioRecorder.current?.pause();
  };

  const resume = () => {
    audioRecorder.current?.resume();
  };

  return { start, stop, pause, resume, status: audioStatus };
}
